<?
    // handles the moving of data to and from the database
    interface RenderableFormElement {
        function Render();
        function GetTitle();
    }    
    abstract class EditableFormElement extends HTMLControl implements RenderableFormElement {
        protected $_editable = false;
        protected $_new = true;
        protected $_dataid = null;
        protected $_structureid = null;
        protected $_data = null;
        
        protected $_title = '';
        protected $_type = '';
        protected $_options = array();
        
        function __construct($structureid,$editable = false,$dataid = null) {
            $structure = DBM::FetchRow("SELECT * FROM listing_structure WHERE id=$structureid;");
            $this->_structureid = $structureid;
            $this->_title = $structure['title'];
            $this->_type = $structure['type'];
            $this->_options = explode(",",$structure['options']);
            $this->_editable = $editable;
        
            if ($dataid) {
                $query = "SELECT * FROM listing_data WHERE structureid=$structureid AND listingid=$dataid;";
                $data = DBM::FetchRow($query);
                $this->_dataid = $dataid;
                
                $this->_data = $data['data'];
            }
        }
        function Save() {
            $query = null;
            if (!$this->_dataid) $query = QueryTools::CreateQuery($this->_fields,"listing_data");
            else $query = QueryTools::CreateQuery($this->_fields,"listing_data","update",$this->_dataid);
            
            DBM::Execute($query);
        }
        
        protected function GetName() {
            return 'formitem_' . $this->_structureid;
        }
        
        // abstract functions
        abstract protected function renderEditable();
        abstract protected function renderStatic();
        abstract protected function renderSearchable();
        
        // RenderableFormElement interface satisfactions
        function GetTitle() { return $this->_title; }
        
        // Custom render function does not implement RenderChildren - therefore 
        // this object does not support child nodes.
        function Render($return = false) {
            if ($this->_editable === 2) {
                if ($return) return $this->renderSearchable();
                else echo $this->renderSearchable();
            }
            else if ($this->_editable == true) {
                if ($return) return $this->renderEditable();
                else echo $this->renderEditable();
            }
            else {
                if ($return) return $this->renderStatic();
                else echo $this->renderStatic();
            }
        }
        //////////////////////////////////////////////////
        
        function __get($var) {
            return $this->_fields[$var];
        }
        function __set($var,$value) {
            $this->_fields[$var] = $value;
        }
    }
    
    // these classes handle rendering the controls for entering and viewing data.
    // don't really need constructors - all actual work is done within EditableFormElement,
    // these just handle the rendering of the data
    
    class EditableHeader extends EditableFormElement {
        function _render() {
            return $this->GetTitle();
        }
        function renderStatic() {
            return $this->_render();
        }
        function renderEditable() {
            return $this->_render();
        }
        function renderSearchable() {
            return null;
        }
    }
    
    // for editable checkboxes, the data stores a series of 
    // SettingManager::EncodeSettingName($value) = 1 for all checkboxes that are checked
    class EditableCheckboxes extends EditableFormElement {
        function renderStatic() {
            $list = new HTMLControl("ul");
            
            $preparsedchecked = explode(";",$this->_data);
            foreach ($preparsedchecked as $key => $checkedpart) {
                $parts = explode(":",$checkedpart);
                $checked[$parts[0]] = 1;
            }   
            
            foreach ($this->_options as $possible) {
                if ($checked[SettingManager::EncodeSettingName($possible)])
                    $list->AddChild(new HTMLControl("li",$possible));
                else continue;
            }
            return $list->Render(true);
        }
        function renderEditable() {
            $checkboxes = new HTMLControl("table");
            $checkboxes->SetAttribute('class','blank');
            $cols = Conf::CHECKBOX_COLS;
            
            $prechecked = explode(";",$this->_data);
            $checked = array();
            foreach ($prechecked as $key => $checkedpart) {
                $parts = explode(":",$checkedpart);
                $checked[$parts[0]] = 1;
            }
            
            
            $count = 0;
            $currow = new HTMLControl("tr");
            foreach ($this->_options as $possible) {                
                $td = new HTMLControl("td");
                
                // assuming noone will change the form between now and POST
                $checkbox = new Checkbox($this->GetName() . "_checkbox_$count",$possible,$checked[SettingManager::EncodeSettingName($possible)]);
                $td->AddChild($checkbox);
                
                if ($currow->CountChildren() == $cols) {
                    $checkboxes->AddChild($currow);
                    $currow = new HTMLControl("tr");
                }
                
                $currow->AddChild($td);
                $count++;
            }
            if ($currow->HasChildren()) 
                $checkboxes->AddChild($currow);
                
            return $checkboxes->Render(true);
        }
        function renderSearchable() {
            return $this->renderEditable();
        }
    }
    class EditableCheckbox extends EditableCheckboxes {} 
    class EditableRadio extends EditableFormElement {
        function _render($enabled = false) {
            $radio = new RadioButtons($this->GetName(),$this->_data);
            $disabled = array("disabled" => "disabled");
            foreach ($this->_options as $opt) {
                $radio->AddOption($opt,$opt,(!$enabled ? $disabled : null));
            }
            return $radio->Render(true);
        }
        function renderStatic() {
            return $this->_data;
        }
        function renderEditable() {
            return $this->_render(true);
        }
        function renderSearchable() {
            // need to render as checkboxes
            $boxes = new EditableCheckboxes($this->_structureid,true);
            return $boxes->renderEditable();
        }
    }
    class EditableSelect extends EditableFormElement {
        function renderStatic() {
            return $this->_data;
        }
        function renderEditable() {
            $dropdown = new DropdownMenu($this->GetName(),$this->_data);
            
            foreach ($this->_options as $option) {
                $dropdown->AddOption($option);
            }
            return $dropdown->Render(true);
        }
        function renderSearchable() {
            // need to render as checkboxes
            $boxes = new EditableCheckboxes($this->_structureid,true);
            return $boxes->renderEditable();
        }
    }
    class EditableTextarea extends EditableFormElement {
        function renderStatic() {
            return $this->_data;
        }
        function renderEditable() {
            $textarea = new Textarea($this->GetName(),$this->_data);
            return $textarea->Render(true);
        }
        function renderSearchable() {
            $field = new EditableTextfield($this->_structureid,true);
            return $field->Render(true);
        }
    }
    class EditableTextfield extends EditableFormElement {
        function renderStatic() {
            return $this->_data;
        }
        function renderEditable() {
            $field = new Textfield($this->GetName());
            $field->attributes->value = $this->_data;
            return $field->Render(true);
        }
        function renderSearchable() {
            return $this->renderEditable();
        }
    }
?>